#include <all_lib.h>
#pragma hdrstop

#include "con_tst.inc"
#include "gh615.h"
#include "gh_TR.h"
#include "gh_WP.h"

char buff1[ 20 ],buff2[ 20 ];
FILE *StdOut;

BOOL AskYesNo( CONSTSTR msg )
  {
    printf( "%s\nAre you shure? (Y/N) ", msg );
    do{
      char ch = getch();
      switch( ch ) {
        case 27:
        case 'N':
        case 'n': printf( "N\n" ); return FALSE;
        case 'Y':
        case 'y': printf( "Y\n" ); return TRUE;
      }
    }while(1);
}

int MYRTLEXP_PT Print( const char *patt,... )
  {  va_list  a;
     int      rc;
     va_start( a, patt );
     rc = vfprintf( StdOut, patt,a );
     va_end( a );
 return rc;
}

void ClearScreen( void )
  {  CONSOLE_SCREEN_BUFFER_INFO ci;
     GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE),&ci );
     ci.srWindow.Bottom -= ci.srWindow.Top;
     for( int n = 0; n < ci.srWindow.Bottom; n++ )
       Print( "\n" );
}

int MYRTLEXP_PT ePrint( const char *patt,... )
  {  va_list  a;

     fprintf( stderr, "\nERROR: " );

     va_start( a, patt );
     vfprintf( stderr, patt,a );
     va_end( a );
     fprintf( stderr, "\n" );

     if ( FIO_ERRORN != ERROR_SUCCESS )
       fprintf( stderr, "Error is: %s\n", FIO_ERROR );
      else
       fprintf( stderr, "\n" );

 return 0;
}

int MYRTLEXP_PT Say( const char *patt,... )
  {  va_list  a;
     va_start( a, patt );
     vfprintf( stderr, patt, a );
     va_end( a );
 return 0;
}

/**********************************************************************
 DoDelAllTracks
**********************************************************************/
void DoDelAllTracks( GH615& gh )
  {
     if ( !gh.QueryTracks() ) {
       ePrint( "!tl" );
       return;
     }

     if ( !gh.Tracks.Count() ) {
       Print( "Device has no saved tracks. Where are to delete.\n" );
       return;
     }

     Print( "Device has %d saved tracks\n", gh.Tracks.Count() );
     if ( !AskYesNo( "Delete all track data?" ) ) return;

     if ( !gh.DelAllTracks( INFINITE ) )
       ePrint( "!del tracks" );
      else
       Print( "Delete track data SUCCESSFULL\n" );
}
/**********************************************************************
 DoInfo
**********************************************************************/
void DoInfo( GH615& gh )
  {
     if ( !gh.QueryInfo() ) {
       ePrint( "!gi" );
       return;
     }

     {  PCGH615_DeviceInfo p = &gh.DeviceInfo;
        Print( "--------- GH615 Device info -------\n"
                "     Name: %s\n"
                "  Version: %d.%d\n"
                " Firmware: %s\n"
                "User name: %s\n"
                "    Birth: %s\n"
                "   Genger: %s\n"
                "   Age is: %d\n"
                "   Weight: %d (%d kg)\n"
                "   Height: %d (%d sm)\n"
                "Waypoints: %d\n"
                "   Tracks: %d\n"
                "",
                p->DeviceName,
                p->Version / 100, p->Version % 100,
                p->Firmware,
                p->User,
                p->Birth.GetStr(NULL,0),
                p->SexMale ? "MALE" : "FEMALE",
                p->Age,
                p->WeightPounds, p->WeightKilo,
                p->HeightInch, p->HeightCm,
                p->WpCount,
                p->TrCount,
                0 );
     }
}

/**********************************************************************
 DoTrackList
**********************************************************************/
void DoTrackList( GH615& gh )
  {
     if ( !gh.QueryTracks() ) {
       ePrint( "!tl" );
       return;
     }

     Print( "Tracks: %d\n", gh.Tracks.Count() );
     if ( gh.Tracks.Count() ) {
       Print( "id  Time                 Duration Distance   Cal    TopSp Points\n" );

       for( int n = 0; n < gh.Tracks.Count(); n++ ) {
         PGH615_Track p = gh.Tracks[n];
         Print( "%03d %s %03d:%02d:%02d %8s %5d %8s %5d\n",
                 p->Id,
                 p->Time.GetStr(NULL,0),
                 p->Duration.hour, p->Duration.min, p->Duration.sec,
                 FormatDouble( p->Distance, buff1, NULL ),
                 p->Calories,
                 FormatDouble( p->TopSpeed, NULL, NULL ),
                 p->nPoints );
       }
       Say( "Tracks: %d\n", gh.Tracks.Count() );
     }
}

/**********************************************************************
 DoWPList
**********************************************************************/
void DoWPList( GH615& gh )
  {
     if ( !gh.QueryWaypoints() ) {
       ePrint( "!get WP" );
       return;
     }

     Say( "Waypoints: %d\n", gh.Waypoints.Count() );
     if ( gh.Waypoints.Count() ) {
       Print( "Name,     Type,  Alt,  Lat,        Lon\n" );

       for( int n = 0; n < gh.Waypoints.Count(); n++ ) {
         PGH615_Waypoint p = gh.Waypoints[n];
         Print( " %-8s, %4d, %4.2lf, %10s, %10s\n",
                 p->Name,
                 p->Type,
                 p->Alt,
                 FormatDouble( p->Lat, NULL, "%3.6lf" ),
                 FormatDouble( p->Lon, buff1, "%3.6lf" ) );
       }
       Say( "Waypoints: %d\n", gh.Waypoints.Count() );
     }
}

/**********************************************************************
 DoGetTrack
**********************************************************************/
void DoGetTrack( GH615& gh, int id )
  {
     Say( "Track: %d\n", id );
     if ( !gh.QueryTrack( id ) ) {
       ePrint( "!gt" );
       return;
     }
     Say( "Points: %d\n", gh.TrackPoints.Count() );

     if ( gh.TrackPoints.Count() ) {
       Print( "Lat,       Lon,        Alt,  H\\R,  Int,  Speed,  Time\n" );
       for( int n = 0; n < gh.TrackPoints.Count(); n++ ) {
         PGH615_TrackPoint p = gh.TrackPoints[n];

         Print( "%8s, %8s, %4.2lf, %4d, %4d, %6s,  %s\n",
                 FormatDouble( p->Lat, NULL, "%3.6lf" ),
                 FormatDouble( p->Lon, buff1, "%3.6lf" ),
                 p->Alt,
                 p->HeartRate, p->Interval,
                 FormatDouble( p->Speed, buff2, "%3.2lf" ),
                 p->Time.GetStr(NULL,0)
                  );

       }
       Say( "Points: %d\n", gh.TrackPoints.Count() );
     }
}

/**********************************************************************
 DoExportTracks
**********************************************************************/
void DoExportTracks( GH615& gh )
  {  FILE *out = StdOut;

     if ( !gh.QueryTracks() ) {
       ePrint( "!tl" );
       return;
     }

     try{
       for( int n = 0; n < gh.Tracks.Count(); n++ ) {
         PGH615_Track pt = gh.Tracks[n];
         CONSTSTR m = Message("Track_%d (%s).csv",pt->Id,pt->Time.GetStr(NULL,0,"%d-%m-%Y %H_%M_%S"));
         StdOut = fopen( m, "wt" );
         if ( !StdOut ) {
           ePrint( "Cant create output file for track %d (%s)", pt->Id, m );
           return;
         }

         Say( "Store track data to: %s\n", m );
         DoGetTrack( gh, pt->Id );
         fclose( StdOut );
       }
     }__finally{
       StdOut = out;
     }
}
/**********************************************************************
 WPUpload
**********************************************************************/
static CONSTSTR GetCol( CONSTSTR m, int num )
  {
     m = StrGetCol( m, num, "," );
     while( isspace(*m) )
       m++;
 return m;
}

void DoWPUpload( GH615& gh, CONSTSTR file )
  {  Say( "Import waypoints from file: %s\n", file );
     FILE *f = fopen( file, "r" );
     if ( !f ) {
      ePrint( "!open file" );
      return;
     }

     char buff[ 1000 ], *m;
     BOOL hdr = TRUE;

     //Skip header

     GH615_Waypoints ar;

     //Get data
     while( !feof(f) && fgets(buff,sizeof(buff),f) != NULL ) {
       m = strchr( buff,'\r' ); if ( m ) *m = 0;
       m = strchr( buff,'\n' ); if ( m ) *m = 0;
       for( m = buff; strchr( " \t\b", *m ) != NULL; )
         m++;
       if ( !*m || *m == '#' ) continue;

       if ( hdr ) {
         hdr = FALSE;
         continue;
       }

       if ( StrColCount(buff,",") != 5 ) {
         ePrint( "Invalid input line: [%s]\n", buff );
         continue;
       }

       GH615_Waypoint wp;

       TStrCpy( wp.Name, GetCol(m,1) );
       wp.Type = (GH615Waypoints_t)Str2Digit( GetCol(m,2), 10, ghwpNONE );
       if ( wp.Type == ghwpNONE ) {
         ePrint( "Invalid type" );
         continue;
       }
       wp.Alt = atof( GetCol(m,3) );
       wp.Lat = atof( GetCol(m,4) );
       wp.Lon = atof( GetCol(m,5) );

       Say( "%3d) %-8s, %4d, %4.2lf, %10s, %10s\n",
            ar.Count()+1,
            wp.Name, wp.Type, wp.Alt,
            FormatDouble( wp.Lat, NULL, "%3.6lf" ),
            FormatDouble( wp.Lon, buff1, "%3.6lf" ) );
       ar.Add( wp );
     }
     fclose( f );
     Say( "Loaded %d waypoints\n", ar.Count() );

     if ( ar.Count() &&
          AskYesNo("Update loaded waypoints in device?") ) {
       Say( "Updated %d of %d waypoints\n",
            gh.SetWaypoints( ar.Items(), ar.Count() ),
            ar.Count() );
     }
}
/**********************************************************************
  Track cvt list
**********************************************************************/
static BOOL TrackFormatValid( int idx )
  {
     for( int n = 0; TRio[n].Name; n++ )
       if ( n == idx ) return TRUE;
 return FALSE;
}

void CVTTrackList( void )
  {
     printf( " N  Import Export Ext    Description\n" );
     for( int n = 0; TRio[n].Name; n++ )
       printf( "%2d)    %c     %c    %-6s %s\n",
               n,
               TRio[n].Import ? 'Y' : 'N', TRio[n].Export ? 'Y' : 'N',
               TRio[n].Ext, TRio[n].Name );
}

void CVTTrack( CONSTSTR m )
  {  int from, to;

     from = Str2Digit( StrGetCol( m, 1, "," ), 10, -1 );
     if ( from == -1 || !TrackFormatValid(from) ) HAbort( "Invalid source format" );
     to = Str2Digit( StrGetCol( m, 2, "," ), 10, -1 );
     if ( to == -1 || !TrackFormatValid(to) ) HAbort( "Invalid destination format" );

     CONSTSTR s = CTArgGetArg(0);
     if ( !s ) HAbort( "Missing source file name" );
     m = CTArgGet("D;DEST");
     if ( !m ) HAbort("Missing destination file name");

     if ( !TRio[from].Import ) HAbort( "Selected source format does not support import" );
     if ( !TRio[to].Export )   HAbort( "Selected destination format does not support export" );

     GH615_TrackPoints ar;

     Say( "Importing [%s] file...\n", s );
     if ( !TRio[from].Import( ar, s ) ) HAbort( "!Import data" );
     Say( "Loaded %d track points.\n", ar.Count() );

     m = Message( "%s.%s", m, TRio[to].Ext );
     Say( "Exporting [%s] file...\n", m );
     if ( !TRio[to].Export( ar, m ) ) HAbort( "!Export data" );
}
/**********************************************************************
  Waypoints cvt list
**********************************************************************/
static BOOL WaypointsFormatValid( int idx )
  {
     for( int n = 0; WPio[n].Name; n++ )
       if ( n == idx ) return TRUE;
 return FALSE;
}

void CVTWaypointsList( void )
  {
     printf( " N  Import Export Ext    Description\n" );
     for( int n = 0; WPio[n].Name; n++ )
       printf( "%2d)    %c     %c    %-6s %s\n",
               n,
               WPio[n].Import ? 'Y' : 'N', WPio[n].Export ? 'Y' : 'N',
               WPio[n].Ext, WPio[n].Name );
}

void CVTWaypoints( CONSTSTR m )
  {  int from, to;

     from = Str2Digit( StrGetCol( m, 1, "," ), 10, -1 );
     if ( from == -1 || !WaypointsFormatValid(from) ) HAbort( "Invalid source format" );
     to = Str2Digit( StrGetCol( m, 2, "," ), 10, -1 );
     if ( to == -1 || !WaypointsFormatValid(to) ) HAbort( "Invalid destination format" );

     CONSTSTR s;
     s = CTArgGetArg(0);     if ( !s ) HAbort("Missing source file name");
     m = CTArgGet("D;DEST"); if ( !m ) HAbort("Missing destination file name");

     if ( !WPio[from].Import ) HAbort( "Selected source format does not support import" );
     if ( !WPio[to].Export )   HAbort( "Selected destination format does not support export" );

     GH615_Waypoints ar;

     Say( "Importing [%s] file...\n", s );
     if ( !WPio[from].Import( ar, s ) ) HAbort( "!Import data" );
     Say( "Loaded %d track points.\n", ar.Count() );

     m = Message( "%s.%s", m, WPio[to].Ext );
     Say( "Exporting [%s] file...\n", m );
     if ( !WPio[to].Export( ar, m ) ) HAbort( "!Export data" );
}
/**********************************************************************
 TST
**********************************************************************/
void DoTST( GH615& gh )
  {
/*
static GH615_Waypoint wps[] = {
  { "01",  (GH615Waypoints_t)1, 250, 56.821645, 60.596635 },
  { "02", (GH615Waypoints_t)1,  250, 56.821563, 60.594567 },
};

     Say( "Updated %d of %d waypoints\n",
          gh.SetWaypoints( wps, ARRAY_SIZE(wps) ),
          ARRAY_SIZE(wps) );
*/
     gh.TST();
}
/**********************************************************************
 MAIN
**********************************************************************/
struct A {
  bool __fastcall idProgress( GH615 *Sender, int Pc ) {
    Say( "Progressing: %3d%%  %c", Pc, Pc == 100?'\n':'\r' );

    while( kbhit() )
      if ( getch() == 27 )
        return false;
    return true;
  }
};

/*
void DoCmd( CONSTSTR nm, LPBYTE cmd, DWORD len )
  {
     Print( "Write cmd [%s]...\n", nm );
     port.Write( cmd, len, INFINITE );

     Print( "Read resp...\n" );
     BYTE response[ 1024 ];
     int cn;

     cn = port.Read( response, sizeof(response), 500 );
     Print( "Res [%d]:\n", cn );
     PDump( response, cn, 0 );
}

    BYTE tracklist[] = { 0x02, 0x00, 0x01, 0x78, 0x79 };
    DoCmd( "tracklist", tracklist, 5 );

    BYTE cmd_DelAllTracks[] = { 2, 0, 3, 0x79, 0, 0x64, 0x1E };
    DoCmd( "cmd_DelAllTracks", cmd_DelAllTracks, 7 );

    BYTE cmd_RequsetFirstTrack[] = { 2, 0, 3, 0x80, 0, 0x64, 0xE7 };
    DoCmd( "cmd_RequsetFirstTrack", cmd_RequsetFirstTrack, 7 );

    BYTE cmd_RequestNextTrack[] = { 2, 0, 1, 0x81, 0x80 };
    DoCmd( "cmd_RequestNextTrack", cmd_RequestNextTrack, 5 );

    BYTE cmd_GetCurrentTrackSegment[] = { 2, 0, 1, 0x82, 0x83 };
    DoCmd( "cmd_GetCurrentTrackSegment", cmd_GetCurrentTrackSegment, 5 );
*/

void main( int argc, char *argv[] )
  {  CONSTSTR  m;

     CTArgInit(argc,argv,FALSE);
     if ( argc < 2 || CTArgCheck("?") ) {
       m = FNameOnly(argv[0]);
       printf( "Utility for GH615B GlobalSat GPS Watch\n"
               "\n"
               "       USAGE: %s <port>|<file> [<command>] [<options>]\n"
               "\n"
               " Parameters:\n"
               "  <port>                - number of port to use (digit 1..XX)\n"
               "  <file>                - set source file name for convertion operations\n"
               "\n"
               " Commands:\n"
               "{Device communication}\n"
               "  -<I>nfo               - list device info\n"
               "  -WP                   - list waypoints\n"
               "  -Tracks               - list tracks\n"
               "  -Track=<ID>           - list track points\n"
               "  -TrackExport          - export all tracks to CSV\n"
               "  -WPUpload=<scv file>  - update device waypoints from CSV file\n"
               "{Convertion}\n"
               "  -CVTL                 - list supported track formats\n"
               "  -CVT=<from>,<to>      - convert track file from one format to another\n"
               "  -CVWL                 - list supported waypoints formats\n"
               "  -CVW=<from>,<to>      - convert waypoint file from one format to another\n"
               "\n"
               " Options:\n"
               "  -<CT>imeout=<val>     - set char-wait timeout\n"
               "  -<D>est=<file>        - set destination file name\n"
               "\n"
               " Samples:\n"
               "  %s 3\n"
               "    Start interactive communication with device at COM3\n"
               "  %s -i 3\n"
               "    Display information from device at COM3\n"
               "  %s Track_10.csv -cvt=0,2 -d=out\n"
               "    Convert track file from format with index \'0\' to format with index \'2\' and put result into file \'out\' (default extension for format \'2\' will be added)\n"
               "  %s 3 -t=10 -ct=150\n"
               "    List track points for track with id \'10\' and use \'150\' ms as char wait timeout.\n"
               "",
               m,
               m, m, m, m );
       return;
     }

     StdOut = stdout;

     do{
       if ( CTArgCheck("CVTL") )         CVTTrackList(); else
       if ( (m=CTArgGet("CVT")) != NULL ) CVTTrack( m ); else
       if ( CTArgCheck("CVT") )
         printf( "Missing track convetion types! Use CvT=<from>,<to> syntax.\n" );
        else
       if ( CTArgCheck("CVWL") )         CVTWaypointsList(); else
       if ( (m=CTArgGet("CVW")) != NULL ) CVTWaypoints( m ); else
       if ( CTArgCheck("CVW") )
         printf( "Missing waypoints convetion types! Use CvW=<from>,<to> syntax.\n" );
        else
         break;

       return;
     }while(0);

     m = CTArgGet("CT;CTimeout");
     GH615 gh( atoi(CTArgGetArg(0)), m ? atoi(m) : 100 );

     A a;
     gh.OnProgress = a.idProgress;

     if ( CTArgCheck("TST") ) {
       DoTST( gh );
     } else
     if ( CTArgCheck("TrackExport") ) {
       DoExportTracks( gh );
     } else
     if ( CTArgCheck("I;INFO") ) {
       DoInfo( gh );
     } else
     if ( CTArgCheck("WP") ) {
       DoWPList( gh );
     } else
     if ( CTArgCheck("TRACKS") ) {
       DoTrackList( gh );
     } else
     if ( (m=CTArgGet("TRACK")) != NULL ) {
       DoGetTrack( gh, atoi(m) );
     } else
     if ( (m=CTArgGet("WPUpload")) != NULL ) {
       DoWPUpload( gh, m );
     } else {
       char ch;
       while(1) {
         while( kbhit() ) getch();
         Print( "\n"
                "Waypoints list     - W\n"
                "Track list         - T\n"
                "Info               - I\n"
                "Track points       - R\n"
                "Export all tracks  - X\n"
                "Del all track data - D\n"
                "\n"
                "Quit               - Q, ESC\n"
                "Clear screen       - SPACE\n"
                "-----------------------------\n"
                "Command: " );
         ch = toupper(getch());
         Print( "%c\n",ch );

         switch( ch ) {
           case 'Q':
           case  27: return;

           case ' ': ClearScreen(); break;

           case 'I': DoInfo( gh ); break;
           case 'W': DoWPList( gh ); break;
           case 'T': DoTrackList( gh ); break;
           case 'X': DoExportTracks( gh ); break;

           case 'D': DoDelAllTracks(gh); break;

           case 'R': { int idx;
                       Print( "Enter track ID: " );
                       scanf( "%d", &idx );
                       Print( "\n" );
                       DoGetTrack( gh, idx );
                     }
                   break;

           default: Print( "Unknown command!!\n" );
       }
     }
  }
}
